/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package pt.iscte.iul.dcti.aa.algorithm.qlearning;

import agente.MemEAV;
import ambiente.Accao;
import java.util.List;
import java.util.Random;

/**
 *
 * @author Gedsimon Pereira
 * @author Simão Fernandes
 */
public class QLearning<E> {

    private final double alfa;
    private final double gama;
    private final double epsilon;
    private final List<Accao> accoes;
    private MemEAV<E, Accao, Double> matrizEsparsa = new MemEAV<E, Accao, Double>(new Double(0));

    public QLearning(List<Accao> accoes, double alfa, double gama, double epsilon) {
        this.alfa = alfa;
        this.gama = gama;
        this.epsilon = epsilon;
        this.accoes = accoes;
    }

    public void assimilar(E estado, Accao acao, E sn, double reforco) {
        Accao aMax = maxAccao(sn);
        double valor = matrizEsparsa.get(estado, acao) + alfa * (reforco + gama * (matrizEsparsa.get(sn, aMax) - matrizEsparsa.get(estado, acao)));
        matrizEsparsa.set(estado, acao, valor);

    }

    public Accao seleccionarAccao(E estado) {

        if (Math.random() > epsilon) {
            return maxAccao(estado);
        } else {
            return gerarAccaoAleatoria();
        }
    }

    public Accao gerarAccaoAleatoria() {
        return accoes.get(new Random().nextInt(accoes.size()));
    }

    public Accao maxAccao(E estado) {
        Accao aMax = null;
        double qMax = Double.NEGATIVE_INFINITY;

        for (Accao accao : accoes) {
            double qa = matrizEsparsa.get(estado, accao);
            if (qa > qMax) {
                qMax = qa;
                aMax = accao;
            }
        }

        return aMax;
    }
}
